package com.flowable;

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.junit.jupiter.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 让@BeforeAll在非静态方法中使用
class AskForLeaveSharedProcessTest {

    private static final Logger log = LoggerFactory.getLogger(AskForLeaveSharedProcessTest.class);
    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    @Test
    void All(){
        // 查询历史流程实例
        List<HistoricProcessInstance> historicInstances = historyService
                .createHistoricProcessInstanceQuery()
                .finished()
                .list();

       historicInstances.forEach(historicProcessInstance -> {
           log.info("历史流程:{}",historicProcessInstance);
       });

        // 查询历史任务
        List<HistoricTaskInstance> historicTasks = historyService
                .createHistoricTaskInstanceQuery()
                .taskAssignee("john")
                .list();

        historicTasks.forEach(historicTaskInstance -> {
            log.info("历史任务:{}",historicTaskInstance);
        });

    }

    private static final String PROCESS_DEFINITION_KEY = "ask_for_leave";
    private static final String EMPLOYEE = "employee1";
    private static final String TEAM_LEADER = "zuzhang1";
    private static final String MANAGER = "manager1";

    private String processInstanceId; // 共享的流程实例ID

    /**
     * 初始化方法：整个测试类只执行一次
     * 1. 部署流程定义
     * 2. 启动一个共享的流程实例
     */
    @BeforeAll
    void globalSetup() {
        // 1. 部署流程（如果已部署则跳过）
        if (repositoryService.createDeploymentQuery().count() == 0) {
            repositoryService.createDeployment()
                    .addClasspathResource("processes/ask_for_leave.bpmn20.xml")
                    .deploy();
        }

        // 2. 启动一个共享流程实例
        Map<String, Object> vars = new HashMap<>();
        vars.put("leaveTask", EMPLOYEE);
        vars.put("name", "测试用户");
        vars.put("reason", "集成测试");
        vars.put("days", 3);

        ProcessInstance instance = runtimeService.startProcessInstanceByKey(
                PROCESS_DEFINITION_KEY,
                vars
        );
        processInstanceId = instance.getId();
        System.out.println("全局流程实例ID: " + processInstanceId);
    }

    /**
     * 测试查询初始任务（员工节点）
     * 验证：
     * 1. 能查询到任务
     * 2. 任务名称是"请假"
     * 3. 处理人是employee1
     */
    @Test
    void testInitialTask() {
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        assertNotNull(task, "未找到初始任务");
        assertEquals("请假", task.getName());
        assertEquals(EMPLOYEE, task.getAssignee());
        System.out.println("当前任务: " + task.getName());
    }

    /**
     * 测试完成员工任务
     * 验证：
     * 1. 完成任务后流程进入组长审批节点
     */
    @Test
    void testCompleteEmployeeTask() {
        // 获取并完成任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(EMPLOYEE)
                .singleResult();
        taskService.complete(task.getId());

        // 验证下一节点
        Task nextTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        assertEquals("组长审核", nextTask.getName());
        System.out.println("流程进入: " + nextTask.getName());
    }

    /**
     * 测试组长审批通过
     * 验证：
     * 1. 审批后流程进入经理节点
     */
    @Test
    @Disabled("需先执行testCompleteEmployeeTask")
    void testTeamLeaderApproval() {
        // 先推进到组长节点（如果未执行前置测试需手动完成）
        advanceToTeamLeaderTask();

        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(TEAM_LEADER)
                .singleResult();
        taskService.complete(task.getId(), Map.of("checkResult", "通过"));

        Task nextTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        assertEquals("经理审核", nextTask.getName());
    }

    /**
     * 测试经理审批拒绝
     * 验证：
     * 1. 审批后流程进入发送邮件节点
     */
    @Test
    @Disabled("需先执行前置审批")
    void testManagerRejection() {
        // 推进到经理节点
        advanceToManagerTask();

        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(MANAGER)
                .singleResult();
        taskService.complete(task.getId(), Map.of("checkResult", "拒绝"));

        Task nextTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        assertEquals("发送失败提示", nextTask.getName());
    }

    // ---------- 流程推进工具方法 ----------

    /**
     * 将流程推进到组长审批节点
     */
    private void advanceToTeamLeaderTask() {
        completeAllTasks(EMPLOYEE); // 完成所有员工任务
    }

    /**
     * 将流程推进到经理审批节点
     */
    private void advanceToManagerTask() {
        advanceToTeamLeaderTask();
        completeAllTasks(TEAM_LEADER, "通过"); // 组长通过
    }

    /**
     * 完成指定处理人的所有任务
     */
    private void completeAllTasks(String assignee) {
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(assignee)
                .list();
        tasks.forEach(task -> taskService.complete(task.getId()));
    }

    /**
     * 带变量完成任务
     */
    private void completeAllTasks(String assignee, String checkResult) {
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .taskAssignee(assignee)
                .list();
        tasks.forEach(task ->
                taskService.complete(task.getId(), Map.of("checkResult", checkResult))
        );
    }
}